/*
 * DelegateClassImplementation.java  0.4.0 / Nov 6, 2010
 *
 * Copyright (c) 2010 - 2011, cute4j.com and contributors.
 *
 * This software is licensed under the LGPL version 2.1 license.
 * A copy of this license is included in the file LICENSE-LGPL.txt.
 */
package com.cute4j.tools.ng.delegate;

import java.io.IOException;
import java.io.PrintWriter;

import com.thoughtworks.qdox.model.JavaClass;
import com.thoughtworks.qdox.model.JavaMethod;

import com.cute4j.tools.ng.AbstractNativeFile;
import com.cute4j.tools.ng.NativeFileText;
import com.cute4j.tools.ng.Utils;

/**
 * Delegate Class Implementation.
 *
 * @author Slobodan Vrkacevic
 * @version 0.4.0
 */
class DelegateClassImplementation extends NativeFileText {

// Private Fields. -------------------------------------------------------------

  private final JavaClass javaClass;

// Public Constructors. --------------------------------------------------------

  /**
   * Constructs new DelegateClassImplementation object.
   *
   * @param nativeFile the native file
   * @param javaClass the qdox java class
   */
  public DelegateClassImplementation(AbstractNativeFile nativeFile,
                                     JavaClass javaClass) {
    super(nativeFile);
    this.javaClass = javaClass;
  }

// Overridden Methods. ---------------------------------------------------------

  /**
   * {@inheritDoc}
   */
  protected void storeContent(PrintWriter pw) throws IOException {
    storeIncludes(pw);
    storeJniCalls(pw);
    storeCallBacks(pw);
  }

// Private Methods. ------------------------------------------------------------

  private void storeIncludes(PrintWriter pw) throws IOException {
    pw.print("#include \"");
    pw.print(Utils.getDelegateName(javaClass));
    pw.println(".h\"");
    pw.println();
  }

  private void storeJniCalls(PrintWriter pw) throws IOException {
    String delegateObjectName = Utils.getDelegateObjectName(javaClass);
    JavaMethod[] methods = javaClass.getMethods();
    boolean[] implementedMethods = new boolean[methods.length];
    for (int i = 0; i < methods.length; i++) {
      JavaMethod method = methods[i];
      if (method.isNative()) {
        String delegateObject = Utils.getNativeTagParameter(method,
                                                            "delegateObject");
        implementedMethods[i] =
            ((Utils.getNativeTagParameter(method, "code") != null) ||
             ((delegateObject != null) &&
              !delegateObjectName.equals(delegateObject)));
      }
    }
    boolean labeled = false;
    for (int i = 0; i < methods.length; i++) {
      JavaMethod method = methods[i];
      if (!implementedMethods[i] && method.isNative() && !method.isStatic() &&
          "_create".equals(method.getName())) {
        if (!labeled) {
          Utils.printBlockComment(pw, Utils.getDelegateName(javaClass) +
                                  " - Protected Constructor.");
          labeled = true;
        }
        pw.println(Utils.getDelegateConstructorComment(method));
        pw.println(Utils.getDelegateConstructorImplementation(method));
      }
    }
    labeled = false;
    for (int i = 0; i < methods.length; i++) {
      JavaMethod method = methods[i];
      if (!implementedMethods[i] && method.isNative() && !method.isStatic() &&
          !"_create".equals(method.getName())) {
        if (!labeled) {
          Utils.printBlockComment(pw, Utils.getDelegateName(javaClass) +
                                  " - Native Calls.");
          labeled = true;
        }
        pw.println(Utils.getDelegateMethodComment(method));
        pw.println(Utils.getDelegateMethodImplementation(method));
      }
    }
    labeled = false;
    for (int i = 0; i < methods.length; i++) {
      JavaMethod method = methods[i];
      if (!implementedMethods[i] && method.isNative() && method.isStatic()) {
        if (!labeled) {
          Utils.printBlockComment(pw, Utils.getDelegateName(javaClass) +
                                  " - Static Native Calls.");
          labeled = true;
        }
        pw.println(Utils.getDelegateMethodComment(method));
        pw.println(Utils.getDelegateMethodImplementation(method));
      }
    }
    for (int i = 0; i < methods.length; i++) {
      JavaMethod method = methods[i];
      if (!implementedMethods[i] && method.isNative() && !method.isStatic() &&
          "_create".equals(method.getName())) {
        if (!labeled) {
          Utils.printBlockComment(pw, Utils.getDelegateName(javaClass) +
                                  " - Static Native Calls.");
          labeled = true;
        }
        pw.println(Utils.getNativeCallNewInstanceMethodComment(method));
        pw.println(Utils.getNativeCallNewInstanceMethodImplementation(method));
      }
    }
  }

  private void storeCallBacks(PrintWriter pw) throws IOException {
    JavaMethod[] methods = javaClass.getMethods();
    boolean labeled = false;
    for (int i = 0; i < methods.length; i++) {
      JavaMethod method = methods[i];
      String methodName = method.getName();
      if (!method.isNative() && (methodName.charAt(0) == '_') &&
          !"true".equals(Utils.getNativeTagParameter(method,
                                                     "overridden"))) {
        if (!labeled) {
          Utils.printBlockComment(pw, Utils.getDelegateName(javaClass) +
                                  " - Native Callbacks.");
          labeled = true;
        }
        pw.println(Utils.getDelegateMethodComment(method));
        pw.println(Utils.getCallbackMethodImplementation(method));
      }
    }
  }

}
